package com.googlecode.bipol.war.session;

import java.io.Serializable;
import java.sql.Timestamp;
import java.util.Date;
import java.util.EnumSet;
import java.util.HashMap;
import java.util.Map;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpSession;
import org.apache.log4j.Logger;
import org.charless.spring.jsonrpc.JsonRpcController;
import com.googlecode.bip.dao.DAOFactory;
import com.googlecode.bip.dao.UserDAO;
import com.googlecode.bip.entity.IGenericUser;
import com.googlecode.bip.entity.Role;
import com.googlecode.bip.entity.impl.EntityHelper;
import com.googlecode.bip.util.RolesIdentifier;
import com.googlecode.bipol.war.services.QuestionManager;
import com.googlecode.bipol.war.services.QuestionManagerImpl;
import com.googlecode.bipol.war.services.SurveyManager;
import com.googlecode.bipol.war.services.SurveyManagerImpl;
import com.googlecode.bipol.war.services.TopicManager;
import com.googlecode.bipol.war.services.TopicManagerImpl;
import com.googlecode.bipol.war.services.UserManager;
import com.googlecode.bipol.war.services.UserManagerImpl;
import com.metaparadigm.jsonrpc.JSONRPCBridge;

/**
 *  JSON-RPC ajaxServices bean
 */
public class BipSession
    extends JsonRpcController
        implements IBipSession, Serializable
{
    private static final long serialVersionUID = 1L;
    private static final transient Logger logger = Logger.getLogger( BipSession.class );
    private IGenericUser    iGenericUser    = null;
    private Timestamp       userDate        = null;

    // example of extension (?)
    //private Set<String> registerObjectSet = new HashSet<String>();

    public BipSession()
    {
        super();
    }

    /**
     * TODO: Doc
     */
    protected void registerSessionAjaxServicesImpl( final JSONRPCBridge bridge ) throws Exception
    {
        try {
            bridge.enableReferences();
            //bridge.registerCallableReference(.class);
            bridge.setDebug( true );

            //this.userName = getHttpServletRequest().getRemoteUser();

            if( logger.isDebugEnabled() ) {
                logger.debug( "JSON Session bridge '" + bridge + "'" );
                logger.debug( "registerSessionAjaxServicesImpl : " + this.toString() );
                logger.debug( "registerSessionAjaxServicesImpl UserName=" + this.getUsername() );
                }

            final UserDAO userDAO   = DAOFactory.getDAOFactory().getUserDAO();
            this.iGenericUser       = userDAO.findGenericUser( getHttpServletRequest() );

            // Put IGenericUser on Session ???
            if( getGenericUser() != null ) {
                getHttpServletRequest().getSession().setAttribute( "IGenericUser", getGenericUser() );
                }
            else {
                getHttpServletRequest().getSession().removeAttribute( "IGenericUser" );
                }

            registerObject(bridge, "SurveyManager", new SurveyManagerImpl( this ), SurveyManager.class);
            registerObject(bridge, "TopicManager", new TopicManagerImpl(), TopicManager.class );
            registerObject(bridge, new QuestionManagerImpl(), QuestionManager.class);
            registerObject(bridge, "UserManager", new UserManagerImpl( this ), UserManager.class);

            if( logger.isDebugEnabled() ) {
                logger.debug("registerSessionAjaxServicesImpl() done");
                }
            }
        catch( Exception e ) {
            logger.fatal( "**** registerSessionAjaxServicesImpl", e );

            throw e;
            }

        if( logger.isDebugEnabled() ) {
            logger.debug( "------ BipSession: " + this );
            }
    }

    private <T extends Serializable> void registerObject(
            final JSONRPCBridge   bridge,
            final String          name,
            final T               object,
            final Class<T>        interfaceClass
            )
    {
//        if( registerObjectSet.contains( name ) ) {
//            logger.warn( "Object already registred: " + name );
//            // throw something ???
//            }
        if( logger.isDebugEnabled() ) {
            logger.debug( "registerObject " + name + " = " + object );
            }

        bridge.registerObject( name, object, interfaceClass );
//        registerObjectSet.add( name );
    }

    private <T extends Serializable> void registerObject(
            final JSONRPCBridge   bridge,
            final T               object,
            final Class<T>        interfaceClass
            )
    {
        bridge.registerObject( interfaceClass.getSimpleName(), object, interfaceClass );
    }

//    /**
//     * For debugging propose ONLY
//     *
//     * @return an unmodifiable Set of registered object names
//     */
//    public Set<String> getRegistredObjectNamesOnJSONRPCBridge()
//    {
//        return Collections.unmodifiableSet( registerObjectSet );
//    }

    /* (non-Javadoc)
     * @see com.googlecode.bipol.war.session.IBipolSession#getUsername()
     */
    @Override
    //final
    public String getUsername()
    {
        return getHttpServletRequest().getRemoteUser();
    }

    @Override
    //final
    public Map<String,String> getUserProperties()
    {
        Map<String,String> props = new HashMap<String,String>();

        props.put( "name", this.getUsername() );

        for( Role role : EnumSet.allOf( Role.class ) ) {
            if( getHttpServletRequest().isUserInRole( role.name() ) ) {
                props.put( "role", role.name() );
                break;
                }
            }

        return props;
    }

    @Override
    public boolean isBipUser()
    {
        return RolesIdentifier.isUserInRole( getHttpServletRequest(), Role.BIP_USER );
    }

    @Override
    public boolean isBipAuthor()
    {
        return RolesIdentifier.isUserInRole( getHttpServletRequest(), Role.BIP_AUTHOR );
    }

    @Override
    public boolean isBipReferent()
    {
        return RolesIdentifier.isUserInRole(getHttpServletRequest(), Role.BIP_REF );
    }

    @Override
    public boolean isBipSuperAdministrator()
    {
        return RolesIdentifier.isUserInRole( getHttpServletRequest(), Role.BIP_ADMIN );
    }

    @Override
    public void invalidateSession()
    {
        HttpServletRequest  request     = getHttpServletRequest();
        HttpSession         httpSession = request.getSession( false );

        if( httpSession != null ) {
            httpSession.invalidate();
            }

        try {
            request.logout();
            }
        catch( ServletException e ) {
            logger.warn( "request.logout() error", e );
            }
    }

    @Override
    public IGenericUser getGenericUser()
    {
        return iGenericUser;
    }

    @Override
    public Timestamp getUserDate()
    {
        if( this.userDate == null ) {
            this.userDate = EntityHelper.getNormalizedTimestamp( new Date() );
            }

        return this.userDate;
    }

    @Override
    public void setUserDate( final Date date )
    {
        this.userDate = EntityHelper.getNormalizedTimestamp( date );
    }

    /* (non-Javadoc)
     * @see java.lang.Object#toString()
     */
    @Override
    public String toString()
    {
        return "BipSession [getUsername()=" + getUsername()
                + ", getUserProperties()=" + getUserProperties()
                + ", isBipUser()=" + isBipUser()
                + ", isBipAuthor()=" + isBipAuthor()
                + ", isBipReferent()=" + isBipReferent()
                + ", isBipSuperAdministrator()=" + isBipSuperAdministrator()
                + ", getGenericUser()=" + getGenericUser()
                + ", getUserDate()=" + getUserDate()
                + "]";
    }

}

